﻿using Common;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;

namespace Core.Extensions.Authorizations.Helpers
{
    public class JwtHelper
    {
        /// <summary>
        /// 颁发JWT字符串
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJwt(TokenModelJwt tokenModel)
        {
            //Token是谁颁发的
            string issuer = Appsettings.app(new string[] { "Audience","Issuer" });

            //Token给那些客户端去使用
            string aud = Appsettings.app(new string[] { "Audience", "Audience" });

            //用于加密的key 必须是16个字符以上，要大于128个字节
            string secret =  Appsettings.app(new string[] { "Audience", "Secret" });
            var claims = new List<Claim> {
                /*
                 * 特别重要：
                   1、这里将用户的部分信息，比如 uid 存到了Claim 中，如果你想知道如何在其他地方将这个 uid从 Token 中取出来，请看下边的SerializeJwt() 方法，或者在整个解决方案，搜索这个方法，看哪里使用了！
                   2、你也可以研究下 HttpContext.User.Claims ，具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */    
                new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Uid.ToString()),
                new Claim(JwtRegisteredClaimNames.Iss,issuer),
                new Claim(JwtRegisteredClaimNames.Aud,aud),
                new Claim(JwtRegisteredClaimNames.Iat,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                //过期时间
                new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
                new Claim(ClaimTypes.Expiration,DateTime.Now.AddSeconds(1000).ToString())//定义可以分配给使用者的已知声明类型的常数。 此类不能被继承。https://docs.microsoft.com/zh-cn/dotnet/api/system.security.claims.claimtypes?view=netcore-2.2
            };
            //可以将一个用户多个角色全部赋予
            claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

            //密匙（SymmetricSecurityKey 对安全性的要求，密匙的长度太短会报出异常），hs256 对称加密 密匙长度不小于128位 所以需要16个加密字符
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(issuer:issuer,claims:claims, signingCredentials: creds);
            var jwtHandler = new JwtSecurityTokenHandler();
            var encodeJwt = jwtHandler.WriteToken(jwt);
            return encodeJwt;
        }

        /// <summary>
        /// 解析Jwt
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public TokenModelJwt SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            var tokenModelJwt = new TokenModelJwt();
            //token校验
            if (!string.IsNullOrEmpty(jwtStr) && jwtHandler.CanReadToken(jwtStr))
            {
                var jwtToken = jwtHandler.ReadJwtToken(jwtStr);
                object role;
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);

                //jwtToken.Id  Gets the 'value' of the 'JWT ID' claim { jti, ''value' }
                tokenModelJwt = new TokenModelJwt {
                    Uid = string.IsNullOrEmpty(jwtToken.Id) ? 0 : long.Parse(jwtToken.Id),
                    Role = role != null ? role.ToString() : ""
                };
            }
            return tokenModelJwt;
        }

    }

    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModelJwt
    {
        /// <summary>
        /// Id
        /// </summary>
        public long Uid { get; set; }
        /// <summary>
        /// 角色，多个角色请用','(英文逗号)分割
        /// </summary>
        public string Role { get; set; }
        /// <summary>
        /// 职能
        /// </summary>
        public string Work { get; set; }
    }
}
